/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_seek_server.h"
#include "sle_seek_service.h"
#include "sle_adapter_manager.h"
#include "sle_utils_remote_observer_list.h"
#include "sle_hilog.h"
#include "sle_advanced_setting_manager.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
class SleSeekServer::SleSeekServerImpl {
public:
    SleSeekServerImpl();
    ~SleSeekServerImpl();

    SleErrorCode CheckOperation();
    SleErrorCode RegisterSeekCallback(const sptr<ISleSeekCallback> &callback);
    SleErrorCode UnregisterSeekCallback(const sptr<ISleSeekCallback> &callback);
    SleErrorCode StartSeek(SeekParam &param);
    SleErrorCode StopSeek();
    SleErrorCode GetDefaultSeekParamConfig(SleSeekParam &seekParam);
    void SetSeekState(SleSeekState state);

    class SleSeekCallbackImpl;
    std::unique_ptr<SleSeekCallbackImpl> callbackImpl_ = nullptr;

    SleSeekService *seekService_ = nullptr;
    SleAdapterManager *adapterManager_ = nullptr;
    SleRemoteObserverList<ISleSeekCallback> callbacks_;

private:
    SleSeekState seekState_ = SLE_SEEK_ERROR_STATE;
    std::mutex lock_;
};

class SleSeekServer::SleSeekServerImpl::SleSeekCallbackImpl : public ISeekCallback {
public:
    SleSeekCallbackImpl(SleSeekServer::SleSeekServerImpl &impl) : impl_(impl) {};
    ~SleSeekCallbackImpl() override = default;

    void OnSeekStateChange(SleSeekState state) override
    {
        SLE_LOGD("OnSeekStateChange In");
        impl_.SetSeekState(state);
        impl_.callbacks_.ForEach([state](sptr<ISleSeekCallback> callback) {
            callback->OnSeekStateChange(state);
        });
    }

    void OnSeekResult(const SleSeekResult &result) override
    {
#if 0
        SLE_LOGD("OnSeekResult In");
#endif
        SeekResult ret(result);
        impl_.callbacks_.ForEach([&ret](sptr<ISleSeekCallback> callback) {
            callback->OnSeekResult(ret);
        });
    }

private:
    SleSeekServer::SleSeekServerImpl &impl_;
};

SleSeekServer::SleSeekServerImpl::SleSeekServerImpl()
{
    SLE_LOGI("SleSeekServerImpl In");
    callbackImpl_ = std::make_unique<SleSeekCallbackImpl>(*this);
    SLE_ASSERT_AND_RETURN_LOG(callbackImpl_, "callbackImpl null error!");

    seekService_ = SleSeekService::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(seekService_, "seek service instance null error!");

    SleErrorCode ret = seekService_->RegisterSeekCallback(*callbackImpl_.get());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_NO_ERROR, "register seek callback failed!");

    adapterManager_ = SleAdapterManager::GetInstance();
    SLE_ASSERT_AND_RETURN_LOG(adapterManager_, "adapter manager instance null error!");

    seekState_ = SLE_SEEK_DISABLED_STATE;
}
SleSeekServer::SleSeekServerImpl::~SleSeekServerImpl()
{
    SLE_LOGI("~SleSeekServerImpl In");
    SLE_ASSERT_AND_RETURN_LOG(callbackImpl_, "callbackImpl null error!");
    SLE_ASSERT_AND_RETURN_LOG(seekService_, "seek service instance null error!");
    SleErrorCode ret = seekService_->UnregisterSeekCallback(*callbackImpl_.get());
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_NO_ERROR, "unregister seek callback failed!");
}

SleErrorCode SleSeekServer::SleSeekServerImpl::SleSeekServerImpl::CheckOperation()
{
    SLE_ASSERT_AND_RETURN_RET_LOG(seekService_, SLE_ERR_NOT_READY, "seek service instance null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(adapterManager_, SLE_ERR_NOT_READY, "adapter manager instance null error!");
    int32_t state;
    SleErrorCode ret = adapterManager_->GetState(state);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get sle state failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(state == SLE_HOST_STATE_ENABLED, SLE_ERR_STATUS_WRONG,
        "host state(%s) error!", SleDeviceStateStr(state));
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::SleSeekServerImpl::RegisterSeekCallback(const sptr<ISleSeekCallback> &callback)
{
    SLE_LOGD("RegisterSeekCallback In");
    auto func = std::bind(&SleSeekServer::SleSeekServerImpl::UnregisterSeekCallback, this, std::placeholders::_1);
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks_.Register(callback, func), SLE_ERR_FAILED, "register seek callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::SleSeekServerImpl::UnregisterSeekCallback(const sptr<ISleSeekCallback> &callback)
{
    SLE_LOGD("UnregisterSeekCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks_.Unregister(callback), SLE_ERR_FAILED, "unregister seek callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::SleSeekServerImpl::StartSeek(SeekParam &param)
{
    SLE_LOGD("StartSeek In");
    std::lock_guard<std::mutex> lock(lock_);
    SLE_ASSERT_AND_RETURN_RET_LOG(seekState_ == SLE_SEEK_DISABLED_STATE, SLE_ERR_STATUS_WRONG,
        "current seek state(%{public}s) error!", SleSeekStateStr(seekState_));
    SleErrorCode ret = seekService_->StartSeek(param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start seek failed!");
    seekState_ = SLE_SEEK_ENABLING_STATE;
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::SleSeekServerImpl::StopSeek()
{
    SLE_LOGD("StopSeek In");
    std::lock_guard<std::mutex> lock(lock_);
    SLE_ASSERT_AND_RETURN_RET_LOG(seekState_ == SLE_SEEK_ENABLED_STATE, SLE_ERR_STATUS_WRONG,
        "current seek state(%{public}s) error!", SleSeekStateStr(seekState_));
    SleErrorCode ret = seekService_->StopSeek();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "stop seek failed!");
    seekState_ = SLE_SEEK_DISABLING_STATE;
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::SleSeekServerImpl::GetDefaultSeekParamConfig(SleSeekParam &seekParam)
{
    SLE_LOGD("GetDefaultSeekParamConfig In");
    SleErrorCode ret = AdvancedSettingManager::GetInstance()->GetDefaultSeekParamConfig(seekParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get seek param config failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}

void SleSeekServer::SleSeekServerImpl::SetSeekState(SleSeekState state)
{
    std::lock_guard<std::mutex> lock(lock_);
    seekState_ = state;
}

SleSeekServer::SleSeekServer()
{
    SLE_LOGI("SleSeekServer In");
    pimpl_ = std::make_unique<SleSeekServerImpl>();
    SLE_ASSERT_AND_RETURN_LOG(pimpl_, "pimpl null error!");
}

SleSeekServer::~SleSeekServer(){}

SleErrorCode SleSeekServer::RegisterSeekCallback(const sptr<ISleSeekCallback> &callback)
{
    SLE_LOGD("RegisterSeekCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback, SLE_ERR_INVALID_PARAM, "callback null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->RegisterSeekCallback(callback);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "register seek callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::UnregisterSeekCallback(const sptr<ISleSeekCallback> &callback)
{
    SLE_LOGD("UnregisterSeekCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(callback, SLE_ERR_INVALID_PARAM, "callback null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->UnregisterSeekCallback(callback);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "unregister seek callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::StartSeek(SeekParam &param)
{
    SLE_LOGD("StartSeek In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed!");
    ret = pimpl_->StartSeek(param);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "start seek failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::StopSeek()
{
    SLE_LOGD("StopSeek In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed!");
    ret = pimpl_->StopSeek();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "stop seek failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleSeekServer::GetDefaultSeekParamConfig(SleSeekParam &seekParam)
{
    SLE_LOGD("GetDefaultSeekParamConfig In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->CheckOperation();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_CHECKOUT_FAILED, "check operation failed(%{public}d)!", ret);
    ret = pimpl_->GetDefaultSeekParamConfig(seekParam);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, ret, "get seek param config failed(%{public}d)!", ret);
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS